﻿/*!	@file	r_rtti_info.h
	@brief	型情報
Copyright (c) 2009 Yuya Yamaguchi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef _R_RTTI_INFO_H_
#define _R_RTTI_INFO_H_

#include "r_rtti_reflection.h"

namespace r{
	namespace rtti{

		class SelializeResolver;
		class DeSelializeResolver;

		class Reflection;
		class ClassBase;

		//! 実行時型情報を保持するクラス
		/*! 使い方は以下の通り

		まずはヘッダ側はClassBaseから派生し、マクロを使って実行時型情報の宣言をする
		class A : public r::rtti::ClassBase
		{
			RRTTI_REFLECTION_DECLARE
			...
		};

		次にCPP側ではリフレクション情報が無いのであれば
		RRTTI_REFLECTION_IMPLEMENT(A, r::rtti::ClassBase)
		リフレクション情報があれば以下の記述
		RRTTI_REFLECTION_IMPLEMENT(A,
		RRTTI_REFLECTION_IMPLEMENT_TYPE(変数名, _RST("ヒント文字列"), フラグeRRTTIReflectionFlag),
		...,
		)
		RRTTI_REFLECTION_IMPLEMENT_REFLECTION(A, r::rtti::ClassBase)
		*/
		class Info
		{
		public:
			//! コンストラクタ
			/*!
			*/
			Info ( const r_cstr _className, const Info *_baseRTTIInfo, r_size _classSize, Reflection *_reflection = NULL );
		public:
			//! クラス名を取得する
			/*!
			*/
			const r_cstr			getClassName() const;
			//! 基底クラス側のRTTI情報を取得する
			/*!
			*/
			const Info*				getBaseRTTIInfo() const;
			//! クラスのサイズを取得する
			/*!
			*/
			r_size					getClassSize() const;
			//! リフレクション情報を取得する
			/*!
			*/
			const Reflection*		getReflection() const;

			//! このクラスが指定したクラスの派生か調べる
			/*!
			*/
			r_bool					isKindOf ( const Info	*_RTTI ) const;
		protected:
		private:
			//! クラス名
			const	r_cstr			className;
			//! スーパークラスの実行時型情報
			const	Info*			baseRTTIInfo;
			//! このクラスのサイズ
			const	r_size			classSize;	
			//! リフレクション情報
			Reflection*				reflection;
		};

		//! 実行時型情報の取得
		/*! 関数オーバーロードで通常は取得不可能な型に対して実行時型情報の取得が出来るようになります。
		オーバーロードすることで非侵入型のRTTI取得が可能になります。
		*/
		template<class T>static inline	const ::r::rtti::Info*	getRTTI()
		{
			return &T::RTTI;
		}

		template<class T>class TypeRTTI
		{
		public:
			const ::r::rtti::Info*	operator()( const T& types ){
				return types.getRTTIInfo();
			}
		};
		template<class T>class TypeRTTI<T*>
		{
		public:
			const ::r::rtti::Info*	operator()( const T* types ){
				TypeRTTI<T> getRTTIFunc;
				return getRTTIFunc( *types );
			}
		};
		template<class T>static inline	const ::r::rtti::Info*	getRTTI( const T& types )
		{
			TypeRTTI<T> getRTTIFunc;
			return getRTTIFunc( types );
		}
	}
}

#endif // _R_RTTI_INFO_H_
